Load packages

library(tidyverse)
library(readxl)
library(cowplot)

Import data

#Anna's Laptop
#Data <- read_xlsx("~/Desktop/PhysiologyDatabaseVersion5.xlsx", sheet = "T3", na = c("NA", ""))
# Mariana's desktop
#Data <- read_xlsx("/Users/marianaabarcazama/Desktop/Projects/ThermalPerformance/PhysiologyDatabaseVersion5.xlsx", sheet = "T3", na = c("NA", "")) 
# Mariana's laptop
#Data <- read_xlsx("/Users/mar/Desktop/Projects/ThermalPerformance/PhysiologyDatabaseVersion5.xlsx", sheet = "T3", na = c("NA", "")) 

Remove parasitoids and convert character to factor

unique(Data$status)
Error in unique(Data$status) : object 'Data' not found

Calculate development rate

When all larvae in a treatment die, their development time is “NA”, however their development rate should be “0”. The loop below calculates development rate (1/dt) and assigns 0 to all cases where both survival is 0 and development time is “NA”. There is one case in which development time is less than 1, it was rounded to 1.

fast <- filter(Ana, dt < 1)
Ana <- Ana %>% 
  mutate(dt = ifelse(dt < 1, ceiling(dt),dt))
  
sets <- unique(Ana$set) 
rates <- tribble(~set, ~temp, ~dr)
rates2 <- tribble(~set, ~temp, ~dr)
output.table <- tibble()
for(i in seq_along(sets)) {
  
  # make a table per set and determine whether it includes dt data
  seti <- sets[i]
  table <- filter(Ana, set == seti)
  suma <- sum(table$dt, na.rm = T)
  
  # if there is dt data
  if (suma > 0){ 
    
    clement <- filter(table, dt > 0) [["temp"]] # temperatures that allow for development
    hotlim <- max(clement, na.rm = T) # max temp that permits development
    coldlim <- min(clement, na.rm = T) # min temp that permits development
    tempes <- unique(table$temp) # each temperature included in set i
    
    # evaluate each temperature of a set
    for(ii in 1:length(unique(tempes))){
      
      tempii <- tempes[ii]
      
      # if it is lower than coldlim, dr should be zero
      if (table$temp[ii] < coldlim){
        dr <- 0
      output.row <- cbind(set = seti, temp = tempii, dr = dr)
      
      # if it is higher than hotlim, dr should be zero  
      } else if (table$temp[ii] > hotlim) {
        
        dr <- 0
      output.row <- cbind(set = seti, temp = tempii, dr = dr)
      
      # in all other cases, it should be 1/dt
      } else{
        dr <- 1/table$dt[ii]
        output.row <- cbind(set = seti, temp = tempii, dr = dr)
      }
      
      output.table <- rbind(output.table, output.row)
    }
    
    # print stuff to make sure loop is working
    #cat(seti, " ")
    
    
  # if there is no development time in that set, dr should be zero
    } else {
    #cat("set: ", seti, "has no dt \n")
  }
  
}
rates <- output.table
Ana_rates <- left_join(Ana, rates, by = c("set","temp"))
rm(fast, output.row, output.table, rates, rates2, table)
rm(clement, coldlim, dr, hotlim, i, ii, seti, sets, suma, tempes, tempii)

Summary statistics

There are 23 Lepidoptera families in the dataset.

family_sets <-  Ana_rates %>%
  select(set, family) %>% 
  distinct() %>% 
  group_by(family) %>% 
  summarise(sets = length(unique(set)))

Each family is represented by 3 to 405 sets.

ggplot(family_sets, aes(x = reorder(family, - sets), y = sets)) +
  geom_col()+
  geom_hline(yintercept = 50)+
  geom_hline(yintercept = 25, linetype = 2)+
  theme_cowplot()+
  xlab("Family")+
  coord_flip()

Figure 1. Number of sets per family, lines indicate 25 and 50 counts

species <-  Ana_rates %>%
  select(family, sp) %>% 
  distinct() %>% 
  group_by(family) %>% 
  summarise(sp_count = length(unique(sp))) %>% 
  arrange(sp_count)
ggplot(species, aes(x = reorder(family, - sp_count), y = sp_count)) +
  geom_col()+
  geom_hline(yintercept = 10, linetype = 2)+
  geom_hline(yintercept = 5, linetype = 1)+
  theme_cowplot()+
  xlab("Family")+
  ylab("Species")+
  coord_flip()

Figure 2. Number of species per family, lines indicate 5 and 10 species counts.

lifestage_sets <-  Ana_rates %>%
  select(set, lifestage) %>% 
  distinct() %>% 
  group_by(lifestage) %>% 
  summarise(sets = length(unique(set))) %>% 
  arrange(sets)
ggplot(lifestage_sets, aes(x = reorder(lifestage,  sets), y = sets)) +
  geom_col()+
  geom_hline(yintercept = 50)+
  geom_hline(yintercept = 25, linetype = 2)+
  theme_cowplot()+
  xlab("Life stage")+
 
  coord_flip()

Figure 3. Number of sets measuring each lifestage.

lifestage_sets_2 <-  Ana_rates %>%
  select(set, lifestage) %>% 
  distinct() %>% 
  group_by(lifestage) %>% 
  summarise(sets = length(unique(set))) %>% 
  arrange(sets) %>% 
  filter(sets > 4)
ggplot(lifestage_sets_2, aes(x = reorder(lifestage,  sets), y = sets)) +
  geom_col()+
  geom_hline(yintercept = 50)+
  geom_hline(yintercept = 25, linetype = 2)+
  theme_cowplot()+
  xlab("Life stage")+
  
  coord_flip()

Figure 4. Number of sets per lifestage (only lifestages that have at least 5 sets). Lines at 50 and 25.

Sets with both development rate and survival

interval_sets <- Ana_rates %>% 
  group_by(set) %>% 
   
  mutate(dr_sum = sum(dr), 
         n_temps = length(unique(temp)), 
         validcount = sum(!is.na(dt)), 
         validcount_s = sum(!is.na(survival))) %>% 
  filter(n_temps > 3, dr_sum > 0, validcount > 3, validcount_s > 3)
interval_set_list <- unique(interval_sets$set) 
interval <- Ana_rates %>% filter(set %in% interval_set_list)
main_stages <- Ana_rates %>% 
  filter(lifestage == "egg"|lifestage == "larva"|lifestage == "pupa")
main_stages_list <- unique(main_stages$lifestage)
inter <- interval %>% filter(lifestage %in% main_stages_list) 
inter$lifestage <- factor(inter$lifestage)

There are 240 sets with both survival and development time data, from 57 families and 21 lifestages.

For the three main lifestages (egg, larva, pupa), there are 137 sets with both survival and development time data, from 51 species.

Upper Limit Exploration

At the upper thermal ranges contained in the dataset, we are interested in seeing whether we capture the ranges at which survival/development rate begin to decrease. The function below (is.rise) can be applied to development rate and to survival data. It returns a table with 6 columns: just.rise: TURE/FALSE. TRUE for curves missing the range at which performance decreases. ntemp: number of temperature treatments colds: number of temperature treatments below optimum hots: number of temperature treatments above optimum opts: number of temperatures that maximize performance (it’s common to observe multiple survival optima) response: dr/survival

is.rise <- function(table, response){
  ta <- select(table, temp, response) # make a 2 column table
  
  if(nrow(ta) == sum(is.na(ta[,2]))){ # this is to discard sets with only NA                                           # values
    print("No data")
  }else{
    
    # get:
    # maximum performance
    p.large <- max(ta[,2], na.rm = T) 
    # maximum temperature
    t.max <- max(ta[,1], na.rm = T)
    # coldest temperature that maximizes performance
    t.large <- filter(ta, ta[,2] == p.large)[["temp"]][[1]]
    # hotest temperature that maximizes performance (eg, survival can be 1 at 
    # multiple temperatures)
    t.largemax <- max(t.large, na.rm = T)
    # temperatures below the coldest optimum
    colds <- filter(ta, ta[,1] < t.large)
    # temperature above the hotest optimum
    hots <- filter(ta, temp > t.largemax)
    # temperatures that maximize performance
    opts <- filter(ta, ta[,2] == p.large)
    
    #output table
    output <- tibble(just.rise =  t.max == t.largemax, # TRUE for curves missing fall
                     ntemp = nrow(ta), # number of temperature treatments
                     colds = nrow(colds), # number of temps below optimum
                     hots = nrow(hots), # number of temps above optimum
                     opts = nrow(opts), # number of optimum temps
                     response = response) # dr or survival
    output
  }
}

Function to determine if minimum development time occurs at the highest temperature

# Is development time minimum at the highest temperature? ---------------------------------------------------------------
where.min.dt <- function(table){
  ta <- select(table, temp, dt) # make a 2 column table
  
  if(nrow(ta) == sum(is.na(ta[,2]))){ # this is to discard sets with only NA                                           # values
    print("No data")
  }else{
    
    # get:
    # minimum development time
    min.dt <- min(ta$dt, na.rm = T) 
    # maximum temperature
    t.max <- max(ta$temp, na.rm = T)
    
    min.dt.t <- tail(filter(ta, dt == min.dt)[["temp"]])
    
    #output table
    output <- tibble(is.min.at.hottest =  t.max == min.dt.t) # TRUE when min at hotest
    output
  }
}

Calculate the number of sets where the maximum survival is not at the highest measured temp

This code applies the function above to each set, the result is a tibble of tables

qualitycheck <- inter %>% 
  group_by(set) %>% 
  nest() %>% 
  mutate(quality_dr = map2(data, "dr", is.rise), 
         quality_sur = map2(data, "survival", is.rise), 
         is.min.dt.at.max.t = map(data, where.min.dt))

Get only the quality metrics by set

Qmetrics <- select(qualitycheck, set, quality_dr, quality_sur, is.min.dt.at.max.t) %>% 
  unnest( cols = quality_dr, quality_sur, is.min.dt.at.max.t)
unnest() has a new interface. See ?unnest for details.
Try `df %>% unnest(c(quality_dr, quality_sur, is.min.dt.at.max.t))`, with `mutate()` if needed

Number of sets where the minimum development time is not at the highest measured temp: 109

There are 137 sets and most of them 114 report a fall in development time as temperature increases.

There are 148 sets in which the highest survival is not at the highest temperature

Exploratory Graphs

These graphs represent some early data exploration, using the subset of the data that contains both survival and development time for the three main lifestages (egg, larva, pupa).

drhist <- ggplot(Qmetrics, aes(x = hots))+
  geom_histogram() +
  xlab("temps above dr optimum")+
  theme_cowplot()
survivalhist <- ggplot(Qmetrics, aes(x = hots1))+
  geom_histogram() +
  xlab("temps above survival optimum")+
  theme_cowplot()
plot_grid(drhist, survivalhist)
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Figure 6. Histograms showing most sets in the “inter” subset include at least one temperature above the dr optimum and multple above the survival optimum

Scale development time

Function to extract longest development time by set and create a new column with scaled development time. s_dt = 1 - (dt/maxdt).

scale.dt <- function(table){
  maxdt <- max(table$dt, na.rm = T)
  table$s_dt <- 1 - (table$dt/maxdt)
  table
}

Apply the function to each set and add s_dt column (scaled dt)

inter <- inter %>% 
  group_by(set) %>% 
  nest() %>% 
  mutate(s_dt = map(data, scale.dt)) %>% 
  unnest(cols = s_dt) %>% 
  select(-data)

Plot to check that s_dt was calculated properly

ggplot(filter(inter, set == 941|set == 1179| set == 3), aes(x = dt, y = s_dt, col = factor(set)))+
  geom_point()+
  scale_color_viridis_d()+
  theme_cowplot()

dt: development time, s_dt, scaled development time (0 for longest)

egg <- inter[inter$lifestage == "egg", ]
egg$set <- factor(egg$set)
larva <- inter[inter$lifestage == "larva", ]
larva$set <- factor(larva$set)
pupa <- inter[inter$lifestage == "pupa", ]
pupa$set <- factor(pupa$set)

Graph the survival data vs. temperature within each lifestage, with each set as a line, faceted by family

ggplot(data = egg, aes(x = temp, y = survival, color = set, group = set)) + 
  geom_line() +
  facet_wrap(~family) + 
  labs(x = "Temperature", y = "Survival (percentage)", title = "Egg Survival")

Figure 5. Egg survival at a range of temperatures, faceted by family.

ggplot(data = larva, aes(x = temp, y = survival, color = set, group = set)) + 
  geom_line() +
  facet_wrap(~family) + 
  labs(x = "Temperature", y = "Survival (percentage)", title = "Larval Survival")

Figure 6. Larval survival at a range of temperatures, faceted by family.

ggplot(data = pupa, aes(x = temp, y = survival, color = set, group = set)) + 
  geom_line() +
  facet_wrap(~family) + 
  labs(x = "Temperature", y = "Survival (percentage)", title = "Pupal Survival")

Figure 7. Pupal survival at a range of temperatures, faceted by family.

Graph the development time data vs. temperature within each lifestage, with each set as a line, faceted by family

ggplot(data = egg, aes(x = temp, y = dt, color = set, group = set)) + 
  geom_line() +
  facet_wrap(~family) + 
  labs(x = "Temperature", y = "Development time (days)", title = "Egg Development Time")

Figure 8. Egg development time at a range of temperatures, faceted by family.

ggplot(data = larva, aes(x = temp, y = dt, color = set, group = set)) + 
  geom_line() +
  facet_wrap(~family) + 
  labs(x = "Temperature", y = "Development time (days)", title = "Larval Development Time")

Figure 9. Larval development time at a range of temperatures, faceted by family.

ggplot(data = pupa, aes(x = temp, y = dt, color = set, group = set)) + 
  geom_line() +
  facet_wrap(~family) + 
  labs(x = "Temperature", y = "Development time (days)", title = "Pupal Development Time")

Figure 10. Pupal development time at a range of temperatures, faceted by family.

Other exploratory graphs

Noctuids - an example of family-specific graphs

ggplot(data = filter(egg, family == "Noctuidae"), aes(x = temp, y = s_dt, color = set, group = set)) + 
  geom_line() +
  geom_line(data = filter(egg, family == "Noctuidae"), mapping = aes(x = temp, y = survival/100, color = set, group = set), linetype = 2)+
  facet_wrap(~sp) + 
  labs(x = "Temperature", y = "Scaled dt / Survival (dashed)", title = "Noctuid Egg Development and Survival")

Figure 11. Egg development rate and survival in the Noctuidae family, faceted by species.

ggplot(data = filter(larva, family == "Noctuidae"), aes(x = temp, y = s_dt, color = set, group = set)) + 
  geom_line() +
  geom_line(data = filter(larva, family == "Noctuidae"), mapping = aes(x = temp, y = survival/100, color = set, group = set), linetype = 2)+
  facet_wrap(~sp) + 
  labs(x = "Temperature", y = "Scaled dev time / Survival (dashed)", title = "Noctuid Larval Development and Survival")

Figure 12. Larval development rate and survival in the Noctuidae family, faceted by species.

ggplot(data = filter(pupa, family == "Noctuidae"), aes(x = temp, y = s_dt, color = set, group = set)) + 
  geom_line() +
  geom_line(data = filter(pupa, family == "Noctuidae"), mapping = aes(x = temp, y = survival/100, color = set, group = set), linetype = 2)+
  facet_wrap(~sp) + 
  labs(x = "Temperature", y = "Scaled dev time / Survival (dashed)", title = "Noctuid Pupal Development and Survival")

Figure 13. Pupal development rate and survival in the Noctuidae family, faceted by species.

Cummulative survival graphs

For studies that report survival of eggs, larvae and pupa, make graphs of cummulative survival:

# get ids of sets that report survival in all three life stages
egg <- filter(inter, lifestage == "egg", survival >= 0)
egg$set <- factor(egg$set)
larva <- filter(inter, lifestage == "larva",  survival >= 1)
larva$set <- factor(larva$set)
pupa <- filter(inter, lifestage == "pupa",  survival >= 1)
pupa$set <- factor(pupa$set)
egg_ids <- tibble(id = unique(egg$id))
larva_ids <- tibble(id = unique(larva$id))
pupa_ids <- tibble(id = unique(pupa$id))
fullstudies1 <- intersect(egg_ids,larva_ids)
fullstudies <- intersect(fullstudies1,pupa_ids)
# the new table "ontosurvival" contains only those sets
ontosurvival <- inter %>% filter(id %in% fullstudies$id)
ontosurvival$stagenum <- ifelse(ontosurvival$lifestage == "egg", 1, ifelse(ontosurvival$lifestage == "larva",2, 3))

Making a graph with cumulative survival

Here, I calculate cumulative/total suvival at each temp for each set and attempt to plot it.

head(ontosurvival)

combsurvival <- ontosurvival[, c("set", "id", "sp", "lifestage", "temp", "survival", "stagenum")]
LS0tCnRpdGxlOiAiQ29tcGlsYXRpb24gb2YgTGVwaWRvcHRlcmEgdGhlcm1hbCBwZXJmb3JtYW5jZSBjdXJ2ZXMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KIyBMb2FkIHBhY2thZ2VzCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShyZWFkeGwpCmxpYnJhcnkoY293cGxvdCkKYGBgCiAKIyBJbXBvcnQgZGF0YQpgYGB7cn0KI0FubmEncyBMYXB0b3AKI0RhdGEgPC0gcmVhZF94bHN4KCJ+L0Rlc2t0b3AvUGh5c2lvbG9neURhdGFiYXNlVmVyc2lvbjUueGxzeCIsIHNoZWV0ID0gIlQzIiwgbmEgPSBjKCJOQSIsICIiKSkKYGBgCgpgYGB7cn0KIyBNYXJpYW5hJ3MgZGVza3RvcAojRGF0YSA8LSByZWFkX3hsc3goIi9Vc2Vycy9tYXJpYW5hYWJhcmNhemFtYS9EZXNrdG9wL1Byb2plY3RzL1RoZXJtYWxQZXJmb3JtYW5jZS9QaHlzaW9sb2d5RGF0YWJhc2VWZXJzaW9uNS54bHN4Iiwgc2hlZXQgPSAiVDMiLCBuYSA9IGMoIk5BIiwgIiIpKSAKCmBgYAoKYGBge3J9CiMgTWFyaWFuYSdzIGxhcHRvcAojRGF0YSA8LSByZWFkX3hsc3goIi9Vc2Vycy9tYXIvRGVza3RvcC9Qcm9qZWN0cy9UaGVybWFsUGVyZm9ybWFuY2UvUGh5c2lvbG9neURhdGFiYXNlVmVyc2lvbjUueGxzeCIsIHNoZWV0ID0gIlQzIiwgbmEgPSBjKCJOQSIsICIiKSkgCmBgYAoKUmVtb3ZlIHBhcmFzaXRvaWRzIGFuZCBjb252ZXJ0IGNoYXJhY3RlciB0byBmYWN0b3IKYGBge3J9CnVuaXF1ZShEYXRhJHN0YXR1cykKQW5hIDwtIERhdGFbRGF0YSRzdGF0dXMgIT0gInBhcmFzaXRvaWQiLF0Kcm0oRGF0YSkKCiMgY29udmVydCBjaGFyYWN0ZXIgdG8gZmFjdG9yCkFuYSA8LSBBbmEgJT4lCiAgbXV0YXRlX2lmKGlzLmNoYXJhY3RlciwgZmFjdG9yKQpgYGAKCiMjIENhbGN1bGF0ZSBkZXZlbG9wbWVudCByYXRlCldoZW4gYWxsIGxhcnZhZSBpbiBhIHRyZWF0bWVudCBkaWUsIHRoZWlyIGRldmVsb3BtZW50IHRpbWUgaXMgIk5BIiwgaG93ZXZlcgp0aGVpciBkZXZlbG9wbWVudCByYXRlIHNob3VsZCBiZSAiMCIuIFRoZSBsb29wIGJlbG93IGNhbGN1bGF0ZXMgZGV2ZWxvcG1lbnQgcmF0ZSAoMS9kdCkgYW5kIGFzc2lnbnMgMCB0byBhbGwgY2FzZXMgd2hlcmUgYm90aCBzdXJ2aXZhbCBpcyAwIGFuZCBkZXZlbG9wbWVudCB0aW1lIGlzICJOQSIuClRoZXJlIGlzIG9uZSBjYXNlIGluIHdoaWNoIGRldmVsb3BtZW50IHRpbWUgaXMgbGVzcyB0aGFuIDEsIGl0IHdhcyByb3VuZGVkIHRvIDEuCgpgYGB7cn0KZmFzdCA8LSBmaWx0ZXIoQW5hLCBkdCA8IDEpCkFuYSA8LSBBbmEgJT4lIAogIG11dGF0ZShkdCA9IGlmZWxzZShkdCA8IDEsIGNlaWxpbmcoZHQpLGR0KSkKICAKCnNldHMgPC0gdW5pcXVlKEFuYSRzZXQpIApyYXRlcyA8LSB0cmliYmxlKH5zZXQsIH50ZW1wLCB+ZHIpCnJhdGVzMiA8LSB0cmliYmxlKH5zZXQsIH50ZW1wLCB+ZHIpCm91dHB1dC50YWJsZSA8LSB0aWJibGUoKQoKZm9yKGkgaW4gc2VxX2Fsb25nKHNldHMpKSB7CiAgCiAgIyBtYWtlIGEgdGFibGUgcGVyIHNldCBhbmQgZGV0ZXJtaW5lIHdoZXRoZXIgaXQgaW5jbHVkZXMgZHQgZGF0YQogIHNldGkgPC0gc2V0c1tpXQogIHRhYmxlIDwtIGZpbHRlcihBbmEsIHNldCA9PSBzZXRpKQogIHN1bWEgPC0gc3VtKHRhYmxlJGR0LCBuYS5ybSA9IFQpCiAgCiAgIyBpZiB0aGVyZSBpcyBkdCBkYXRhCiAgaWYgKHN1bWEgPiAwKXsgCiAgICAKICAgIGNsZW1lbnQgPC0gZmlsdGVyKHRhYmxlLCBkdCA+IDApIFtbInRlbXAiXV0gIyB0ZW1wZXJhdHVyZXMgdGhhdCBhbGxvdyBmb3IgZGV2ZWxvcG1lbnQKICAgIGhvdGxpbSA8LSBtYXgoY2xlbWVudCwgbmEucm0gPSBUKSAjIG1heCB0ZW1wIHRoYXQgcGVybWl0cyBkZXZlbG9wbWVudAogICAgY29sZGxpbSA8LSBtaW4oY2xlbWVudCwgbmEucm0gPSBUKSAjIG1pbiB0ZW1wIHRoYXQgcGVybWl0cyBkZXZlbG9wbWVudAogICAgdGVtcGVzIDwtIHVuaXF1ZSh0YWJsZSR0ZW1wKSAjIGVhY2ggdGVtcGVyYXR1cmUgaW5jbHVkZWQgaW4gc2V0IGkKICAgIAogICAgIyBldmFsdWF0ZSBlYWNoIHRlbXBlcmF0dXJlIG9mIGEgc2V0CiAgICBmb3IoaWkgaW4gMTpsZW5ndGgodW5pcXVlKHRlbXBlcykpKXsKICAgICAgCiAgICAgIHRlbXBpaSA8LSB0ZW1wZXNbaWldCiAgICAgIAogICAgICAjIGlmIGl0IGlzIGxvd2VyIHRoYW4gY29sZGxpbSwgZHIgc2hvdWxkIGJlIHplcm8KICAgICAgaWYgKHRhYmxlJHRlbXBbaWldIDwgY29sZGxpbSl7CiAgICAgICAgZHIgPC0gMAogICAgICBvdXRwdXQucm93IDwtIGNiaW5kKHNldCA9IHNldGksIHRlbXAgPSB0ZW1waWksIGRyID0gZHIpCiAgICAgIAogICAgICAjIGlmIGl0IGlzIGhpZ2hlciB0aGFuIGhvdGxpbSwgZHIgc2hvdWxkIGJlIHplcm8gIAogICAgICB9IGVsc2UgaWYgKHRhYmxlJHRlbXBbaWldID4gaG90bGltKSB7CiAgICAgICAgCiAgICAgICAgZHIgPC0gMAogICAgICBvdXRwdXQucm93IDwtIGNiaW5kKHNldCA9IHNldGksIHRlbXAgPSB0ZW1waWksIGRyID0gZHIpCiAgICAgIAogICAgICAjIGluIGFsbCBvdGhlciBjYXNlcywgaXQgc2hvdWxkIGJlIDEvZHQKICAgICAgfSBlbHNlewogICAgICAgIGRyIDwtIDEvdGFibGUkZHRbaWldCiAgICAgICAgb3V0cHV0LnJvdyA8LSBjYmluZChzZXQgPSBzZXRpLCB0ZW1wID0gdGVtcGlpLCBkciA9IGRyKQogICAgICB9CiAgICAgIAogICAgICBvdXRwdXQudGFibGUgPC0gcmJpbmQob3V0cHV0LnRhYmxlLCBvdXRwdXQucm93KQogICAgfQogICAgCiAgICAjIHByaW50IHN0dWZmIHRvIG1ha2Ugc3VyZSBsb29wIGlzIHdvcmtpbmcKICAgICNjYXQoc2V0aSwgIiAiKQogICAgCiAgICAKICAjIGlmIHRoZXJlIGlzIG5vIGRldmVsb3BtZW50IHRpbWUgaW4gdGhhdCBzZXQsIGRyIHNob3VsZCBiZSB6ZXJvCiAgICB9IGVsc2UgewogICAgI2NhdCgic2V0OiAiLCBzZXRpLCAiaGFzIG5vIGR0IFxuIikKICB9CiAgCn0KCnJhdGVzIDwtIG91dHB1dC50YWJsZQoKQW5hX3JhdGVzIDwtIGxlZnRfam9pbihBbmEsIHJhdGVzLCBieSA9IGMoInNldCIsInRlbXAiKSkKCnJtKGZhc3QsIG91dHB1dC5yb3csIG91dHB1dC50YWJsZSwgcmF0ZXMsIHJhdGVzMiwgdGFibGUpCnJtKGNsZW1lbnQsIGNvbGRsaW0sIGRyLCBob3RsaW0sIGksIGlpLCBzZXRpLCBzZXRzLCBzdW1hLCB0ZW1wZXMsIHRlbXBpaSkKCmBgYAoKIyBTdW1tYXJ5IHN0YXRpc3RpY3MKVGhlcmUgYXJlIGByIGxlbmd0aCh1bmlxdWUoQW5hX3JhdGVzJGZhbWlseSkpYCBMZXBpZG9wdGVyYSBmYW1pbGllcyBpbiB0aGUgZGF0YXNldC4KYGBge3J9CmZhbWlseV9zZXRzIDwtICBBbmFfcmF0ZXMgJT4lCiAgc2VsZWN0KHNldCwgZmFtaWx5KSAlPiUgCiAgZGlzdGluY3QoKSAlPiUgCiAgZ3JvdXBfYnkoZmFtaWx5KSAlPiUgCiAgc3VtbWFyaXNlKHNldHMgPSBsZW5ndGgodW5pcXVlKHNldCkpKQpgYGAKCkVhY2ggZmFtaWx5IGlzIHJlcHJlc2VudGVkIGJ5IGByIG1pbihmYW1pbHlfc2V0cyRzZXRzKWAgdG8gYHIgbWF4KGZhbWlseV9zZXRzJHNldHMpYCBzZXRzLiAKCmBgYHtyfQpnZ3Bsb3QoZmFtaWx5X3NldHMsIGFlcyh4ID0gcmVvcmRlcihmYW1pbHksIC0gc2V0cyksIHkgPSBzZXRzKSkgKwogIGdlb21fY29sKCkrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gNTApKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDI1LCBsaW5ldHlwZSA9IDIpKwogIHRoZW1lX2Nvd3Bsb3QoKSsKICB4bGFiKCJGYW1pbHkiKSsKICBjb29yZF9mbGlwKCkKYGBgCgpGaWd1cmUgMS4gTnVtYmVyIG9mIHNldHMgcGVyIGZhbWlseSwgbGluZXMgaW5kaWNhdGUgMjUgYW5kIDUwIGNvdW50cwpgYGB7cn0Kc3BlY2llcyA8LSAgQW5hX3JhdGVzICU+JQogIHNlbGVjdChmYW1pbHksIHNwKSAlPiUgCiAgZGlzdGluY3QoKSAlPiUgCiAgZ3JvdXBfYnkoZmFtaWx5KSAlPiUgCiAgc3VtbWFyaXNlKHNwX2NvdW50ID0gbGVuZ3RoKHVuaXF1ZShzcCkpKSAlPiUgCiAgYXJyYW5nZShzcF9jb3VudCkKCmdncGxvdChzcGVjaWVzLCBhZXMoeCA9IHJlb3JkZXIoZmFtaWx5LCAtIHNwX2NvdW50KSwgeSA9IHNwX2NvdW50KSkgKwogIGdlb21fY29sKCkrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMTAsIGxpbmV0eXBlID0gMikrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gNSwgbGluZXR5cGUgPSAxKSsKICB0aGVtZV9jb3dwbG90KCkrCiAgeGxhYigiRmFtaWx5IikrCiAgeWxhYigiU3BlY2llcyIpKwogIGNvb3JkX2ZsaXAoKQpgYGAKCkZpZ3VyZSAyLiBOdW1iZXIgb2Ygc3BlY2llcyBwZXIgZmFtaWx5LCBsaW5lcyBpbmRpY2F0ZSA1IGFuZCAxMCBzcGVjaWVzIGNvdW50cy4KCgpgYGB7cn0KbGlmZXN0YWdlX3NldHMgPC0gIEFuYV9yYXRlcyAlPiUKICBzZWxlY3Qoc2V0LCBsaWZlc3RhZ2UpICU+JSAKICBkaXN0aW5jdCgpICU+JSAKICBncm91cF9ieShsaWZlc3RhZ2UpICU+JSAKICBzdW1tYXJpc2Uoc2V0cyA9IGxlbmd0aCh1bmlxdWUoc2V0KSkpICU+JSAKICBhcnJhbmdlKHNldHMpCgpnZ3Bsb3QobGlmZXN0YWdlX3NldHMsIGFlcyh4ID0gcmVvcmRlcihsaWZlc3RhZ2UsICBzZXRzKSwgeSA9IHNldHMpKSArCiAgZ2VvbV9jb2woKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSA1MCkrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMjUsIGxpbmV0eXBlID0gMikrCiAgdGhlbWVfY293cGxvdCgpKwogIHhsYWIoIkxpZmUgc3RhZ2UiKSsKIAogIGNvb3JkX2ZsaXAoKQpgYGAKCgpGaWd1cmUgMy4gTnVtYmVyIG9mIHNldHMgbWVhc3VyaW5nIGVhY2ggbGlmZXN0YWdlLgoKYGBge3J9CmxpZmVzdGFnZV9zZXRzXzIgPC0gIEFuYV9yYXRlcyAlPiUKICBzZWxlY3Qoc2V0LCBsaWZlc3RhZ2UpICU+JSAKICBkaXN0aW5jdCgpICU+JSAKICBncm91cF9ieShsaWZlc3RhZ2UpICU+JSAKICBzdW1tYXJpc2Uoc2V0cyA9IGxlbmd0aCh1bmlxdWUoc2V0KSkpICU+JSAKICBhcnJhbmdlKHNldHMpICU+JSAKICBmaWx0ZXIoc2V0cyA+IDQpCgpnZ3Bsb3QobGlmZXN0YWdlX3NldHNfMiwgYWVzKHggPSByZW9yZGVyKGxpZmVzdGFnZSwgIHNldHMpLCB5ID0gc2V0cykpICsKICBnZW9tX2NvbCgpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDUwKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAyNSwgbGluZXR5cGUgPSAyKSsKICB0aGVtZV9jb3dwbG90KCkrCiAgeGxhYigiTGlmZSBzdGFnZSIpKwogIAogIGNvb3JkX2ZsaXAoKQpgYGAKRmlndXJlIDQuIE51bWJlciBvZiBzZXRzIHBlciBsaWZlc3RhZ2UgKG9ubHkgbGlmZXN0YWdlcyB0aGF0IGhhdmUgYXQgbGVhc3QgNSBzZXRzKS4gTGluZXMgYXQgNTAgYW5kIDI1LgoKIyBTZXRzIHdpdGggYm90aCBkZXZlbG9wbWVudCByYXRlIGFuZCBzdXJ2aXZhbAoKYGBge3J9CmludGVydmFsX3NldHMgPC0gQW5hX3JhdGVzICU+JSAKICBncm91cF9ieShzZXQpICU+JSAKICAgCiAgbXV0YXRlKGRyX3N1bSA9IHN1bShkciksIAogICAgICAgICBuX3RlbXBzID0gbGVuZ3RoKHVuaXF1ZSh0ZW1wKSksIAogICAgICAgICB2YWxpZGNvdW50ID0gc3VtKCFpcy5uYShkdCkpLCAKICAgICAgICAgdmFsaWRjb3VudF9zID0gc3VtKCFpcy5uYShzdXJ2aXZhbCkpKSAlPiUgCiAgZmlsdGVyKG5fdGVtcHMgPiAzLCBkcl9zdW0gPiAwLCB2YWxpZGNvdW50ID4gMywgdmFsaWRjb3VudF9zID4gMykKCmludGVydmFsX3NldF9saXN0IDwtIHVuaXF1ZShpbnRlcnZhbF9zZXRzJHNldCkgCgppbnRlcnZhbCA8LSBBbmFfcmF0ZXMgJT4lIGZpbHRlcihzZXQgJWluJSBpbnRlcnZhbF9zZXRfbGlzdCkKCm1haW5fc3RhZ2VzIDwtIEFuYV9yYXRlcyAlPiUgCiAgZmlsdGVyKGxpZmVzdGFnZSA9PSAiZWdnInxsaWZlc3RhZ2UgPT0gImxhcnZhInxsaWZlc3RhZ2UgPT0gInB1cGEiKQptYWluX3N0YWdlc19saXN0IDwtIHVuaXF1ZShtYWluX3N0YWdlcyRsaWZlc3RhZ2UpCmludGVyIDwtIGludGVydmFsICU+JSBmaWx0ZXIobGlmZXN0YWdlICVpbiUgbWFpbl9zdGFnZXNfbGlzdCkgCmludGVyJGxpZmVzdGFnZSA8LSBmYWN0b3IoaW50ZXIkbGlmZXN0YWdlKQoKYGBgClRoZXJlIGFyZSBgciBsZW5ndGgodW5pcXVlKGludGVydmFsJHNldCkpYCBzZXRzIHdpdGggYm90aCBzdXJ2aXZhbCBhbmQKZGV2ZWxvcG1lbnQgdGltZSBkYXRhLCBmcm9tIGByIGxlbmd0aCh1bmlxdWUoaW50ZXJ2YWwkc3ApKWAgZmFtaWxpZXMgYW5kCmByIGxlbmd0aCh1bmlxdWUoaW50ZXJ2YWwkbGlmZXN0YWdlKSlgIGxpZmVzdGFnZXMuIAoKRm9yIHRoZSB0aHJlZSBtYWluIGxpZmVzdGFnZXMgKGVnZywgbGFydmEsIHB1cGEpLCB0aGVyZSBhcmUgYHIgbGVuZ3RoKHVuaXF1ZShpbnRlciRzZXQpKWAgc2V0cyB3aXRoIGJvdGggc3Vydml2YWwgYW5kCmRldmVsb3BtZW50IHRpbWUgZGF0YSwgZnJvbSBgciBsZW5ndGgodW5pcXVlKGludGVyJHNwKSlgIHNwZWNpZXMuCgojIFVwcGVyIExpbWl0IEV4cGxvcmF0aW9uIApBdCB0aGUgdXBwZXIgdGhlcm1hbCByYW5nZXMgY29udGFpbmVkIGluIHRoZSBkYXRhc2V0LCB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBzZWVpbmcgd2hldGhlciB3ZSBjYXB0dXJlIHRoZSByYW5nZXMgYXQgd2hpY2ggc3Vydml2YWwvZGV2ZWxvcG1lbnQgcmF0ZSBiZWdpbiB0byBkZWNyZWFzZS4gClRoZSBmdW5jdGlvbiBiZWxvdyAoaXMucmlzZSkgY2FuIGJlIGFwcGxpZWQgdG8gZGV2ZWxvcG1lbnQgcmF0ZSBhbmQgdG8gc3Vydml2YWwgZGF0YS4gSXQgcmV0dXJucyBhIHRhYmxlIHdpdGggNiBjb2x1bW5zOgpqdXN0LnJpc2U6IFRVUkUvRkFMU0UuIFRSVUUgZm9yIGN1cnZlcyBtaXNzaW5nIHRoZSByYW5nZSBhdCB3aGljaCBwZXJmb3JtYW5jZSBkZWNyZWFzZXMuCm50ZW1wOiBudW1iZXIgb2YgdGVtcGVyYXR1cmUgdHJlYXRtZW50cwpjb2xkczogbnVtYmVyIG9mIHRlbXBlcmF0dXJlIHRyZWF0bWVudHMgYmVsb3cgb3B0aW11bQpob3RzOiBudW1iZXIgb2YgdGVtcGVyYXR1cmUgdHJlYXRtZW50cyBhYm92ZSBvcHRpbXVtCm9wdHM6IG51bWJlciBvZiB0ZW1wZXJhdHVyZXMgdGhhdCBtYXhpbWl6ZSBwZXJmb3JtYW5jZSAoaXQncyBjb21tb24gdG8gb2JzZXJ2ZSBtdWx0aXBsZSBzdXJ2aXZhbCBvcHRpbWEpCnJlc3BvbnNlOiBkci9zdXJ2aXZhbAoKYGBge3J9CmlzLnJpc2UgPC0gZnVuY3Rpb24odGFibGUsIHJlc3BvbnNlKXsKICB0YSA8LSBzZWxlY3QodGFibGUsIHRlbXAsIHJlc3BvbnNlKSAjIG1ha2UgYSAyIGNvbHVtbiB0YWJsZQogIAogIGlmKG5yb3codGEpID09IHN1bShpcy5uYSh0YVssMl0pKSl7ICMgdGhpcyBpcyB0byBkaXNjYXJkIHNldHMgd2l0aCBvbmx5IE5BICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdmFsdWVzCiAgICBwcmludCgiTm8gZGF0YSIpCiAgfWVsc2V7CiAgICAKICAgICMgZ2V0OgogICAgIyBtYXhpbXVtIHBlcmZvcm1hbmNlCiAgICBwLmxhcmdlIDwtIG1heCh0YVssMl0sIG5hLnJtID0gVCkgCiAgICAjIG1heGltdW0gdGVtcGVyYXR1cmUKICAgIHQubWF4IDwtIG1heCh0YVssMV0sIG5hLnJtID0gVCkKICAgICMgY29sZGVzdCB0ZW1wZXJhdHVyZSB0aGF0IG1heGltaXplcyBwZXJmb3JtYW5jZQogICAgdC5sYXJnZSA8LSBmaWx0ZXIodGEsIHRhWywyXSA9PSBwLmxhcmdlKVtbInRlbXAiXV1bWzFdXQogICAgIyBob3Rlc3QgdGVtcGVyYXR1cmUgdGhhdCBtYXhpbWl6ZXMgcGVyZm9ybWFuY2UgKGVnLCBzdXJ2aXZhbCBjYW4gYmUgMSBhdCAKICAgICMgbXVsdGlwbGUgdGVtcGVyYXR1cmVzKQogICAgdC5sYXJnZW1heCA8LSBtYXgodC5sYXJnZSwgbmEucm0gPSBUKQogICAgIyB0ZW1wZXJhdHVyZXMgYmVsb3cgdGhlIGNvbGRlc3Qgb3B0aW11bQogICAgY29sZHMgPC0gZmlsdGVyKHRhLCB0YVssMV0gPCB0LmxhcmdlKQogICAgIyB0ZW1wZXJhdHVyZSBhYm92ZSB0aGUgaG90ZXN0IG9wdGltdW0KICAgIGhvdHMgPC0gZmlsdGVyKHRhLCB0ZW1wID4gdC5sYXJnZW1heCkKICAgICMgdGVtcGVyYXR1cmVzIHRoYXQgbWF4aW1pemUgcGVyZm9ybWFuY2UKICAgIG9wdHMgPC0gZmlsdGVyKHRhLCB0YVssMl0gPT0gcC5sYXJnZSkKICAgIAogICAgI291dHB1dCB0YWJsZQogICAgb3V0cHV0IDwtIHRpYmJsZShqdXN0LnJpc2UgPSAgdC5tYXggPT0gdC5sYXJnZW1heCwgIyBUUlVFIGZvciBjdXJ2ZXMgbWlzc2luZyBmYWxsCiAgICAgICAgICAgICAgICAgICAgIG50ZW1wID0gbnJvdyh0YSksICMgbnVtYmVyIG9mIHRlbXBlcmF0dXJlIHRyZWF0bWVudHMKICAgICAgICAgICAgICAgICAgICAgY29sZHMgPSBucm93KGNvbGRzKSwgIyBudW1iZXIgb2YgdGVtcHMgYmVsb3cgb3B0aW11bQogICAgICAgICAgICAgICAgICAgICBob3RzID0gbnJvdyhob3RzKSwgIyBudW1iZXIgb2YgdGVtcHMgYWJvdmUgb3B0aW11bQogICAgICAgICAgICAgICAgICAgICBvcHRzID0gbnJvdyhvcHRzKSwgIyBudW1iZXIgb2Ygb3B0aW11bSB0ZW1wcwogICAgICAgICAgICAgICAgICAgICByZXNwb25zZSA9IHJlc3BvbnNlKSAjIGRyIG9yIHN1cnZpdmFsCiAgICBvdXRwdXQKICB9Cn0KYGBgCgogRnVuY3Rpb24gdG8gZGV0ZXJtaW5lIGlmIG1pbmltdW0gZGV2ZWxvcG1lbnQgdGltZSBvY2N1cnMgYXQgdGhlIGhpZ2hlc3QgdGVtcGVyYXR1cmUKYGBge3J9CiMgSXMgZGV2ZWxvcG1lbnQgdGltZSBtaW5pbXVtIGF0IHRoZSBoaWdoZXN0IHRlbXBlcmF0dXJlPyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0Kd2hlcmUubWluLmR0IDwtIGZ1bmN0aW9uKHRhYmxlKXsKICB0YSA8LSBzZWxlY3QodGFibGUsIHRlbXAsIGR0KSAjIG1ha2UgYSAyIGNvbHVtbiB0YWJsZQogIAogIGlmKG5yb3codGEpID09IHN1bShpcy5uYSh0YVssMl0pKSl7ICMgdGhpcyBpcyB0byBkaXNjYXJkIHNldHMgd2l0aCBvbmx5IE5BICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdmFsdWVzCiAgICBwcmludCgiTm8gZGF0YSIpCiAgfWVsc2V7CiAgICAKICAgICMgZ2V0OgogICAgIyBtaW5pbXVtIGRldmVsb3BtZW50IHRpbWUKICAgIG1pbi5kdCA8LSBtaW4odGEkZHQsIG5hLnJtID0gVCkgCiAgICAjIG1heGltdW0gdGVtcGVyYXR1cmUKICAgIHQubWF4IDwtIG1heCh0YSR0ZW1wLCBuYS5ybSA9IFQpCiAgICAKICAgIG1pbi5kdC50IDwtIHRhaWwoZmlsdGVyKHRhLCBkdCA9PSBtaW4uZHQpW1sidGVtcCJdXSkKICAgIAogICAgI291dHB1dCB0YWJsZQogICAgb3V0cHV0IDwtIHRpYmJsZShpcy5taW4uYXQuaG90dGVzdCA9ICB0Lm1heCA9PSBtaW4uZHQudCkgIyBUUlVFIHdoZW4gbWluIGF0IGhvdGVzdAogICAgb3V0cHV0CiAgfQp9CmBgYAoKIyMgQ2FsY3VsYXRlIHRoZSBudW1iZXIgb2Ygc2V0cyB3aGVyZSB0aGUgbWF4aW11bSBzdXJ2aXZhbCBpcyBub3QgYXQgdGhlIGhpZ2hlc3QgbWVhc3VyZWQgdGVtcApUaGlzIGNvZGUgYXBwbGllcyB0aGUgZnVuY3Rpb24gYWJvdmUgdG8gZWFjaCBzZXQsIHRoZSByZXN1bHQgaXMgYSB0aWJibGUgb2YgdGFibGVzCmBgYHtyfQpxdWFsaXR5Y2hlY2sgPC0gaW50ZXIgJT4lIAogIGdyb3VwX2J5KHNldCkgJT4lIAogIG5lc3QoKSAlPiUgCiAgbXV0YXRlKHF1YWxpdHlfZHIgPSBtYXAyKGRhdGEsICJkciIsIGlzLnJpc2UpLCAKICAgICAgICAgcXVhbGl0eV9zdXIgPSBtYXAyKGRhdGEsICJzdXJ2aXZhbCIsIGlzLnJpc2UpLCAKICAgICAgICAgaXMubWluLmR0LmF0Lm1heC50ID0gbWFwKGRhdGEsIHdoZXJlLm1pbi5kdCkpCmBgYAoKR2V0IG9ubHkgdGhlIHF1YWxpdHkgbWV0cmljcyBieSBzZXQKYGBge3J9ClFtZXRyaWNzIDwtIHNlbGVjdChxdWFsaXR5Y2hlY2ssIHNldCwgcXVhbGl0eV9kciwgcXVhbGl0eV9zdXIsIGlzLm1pbi5kdC5hdC5tYXgudCkgJT4lIAogIHVubmVzdCggY29scyA9IHF1YWxpdHlfZHIsIHF1YWxpdHlfc3VyLCBpcy5taW4uZHQuYXQubWF4LnQpCmBgYAoKCiMjIE51bWJlciBvZiBzZXRzIHdoZXJlIHRoZSBtaW5pbXVtIGRldmVsb3BtZW50IHRpbWUgaXMgbm90IGF0IHRoZSBoaWdoZXN0IG1lYXN1cmVkIHRlbXA6IGByIHN1bShRbWV0cmljcyRpcy5taW4uYXQuaG90dGVzdCA9PSBGQUxTRSlgClRoZXJlIGFyZSBgciBsZW5ndGgodW5pcXVlKFFtZXRyaWNzJHNldCkpYCBzZXRzIGFuZCBtb3N0IG9mIHRoZW0gIGByIHN1bShRbWV0cmljcyRqdXN0LnJpc2UgPT0gRkFMU0UpYCByZXBvcnQgYSBmYWxsIGluIGRldmVsb3BtZW50IHRpbWUgYXMgdGVtcGVyYXR1cmUgaW5jcmVhc2VzLgoKVGhlcmUgYXJlIGByIHN1bShRbWV0cmljcyRqdXN0LnJpc2UxID09IEZBTFNFKWAgc2V0cyBpbiB3aGljaCB0aGUgaGlnaGVzdCBzdXJ2aXZhbCBpcyBub3QgYXQgdGhlIGhpZ2hlc3QgdGVtcGVyYXR1cmUKCiMgV2hhdCBhcmUgdGhlIG1vc3QgcG9wdWxhciB0ZW1wZXJhdHVyZSB0cmVhdG1lbnRzIGltcGxlbWVudGVkPwoKYGBge3J9CmdncGxvdChpbnRlciwgYWVzKHggPSB0ZW1wKSkrCiAgZ2VvbV9iYXIoKSsKICB0aGVtZV9jb3dwbG90KCkrCiAgZmFjZXRfZ3JpZCh+bGlmZXN0YWdlKQpgYGAKRmlndXJlIDUuIEZyZXF1ZW5jeSBvZiB0ZW1wZXJhdHVyZSB0cmVhdG1lbnRzIGluICJpbnRlciIgZGF0YSBzZXQgYnkgbGlmZSBzdGFnZS4gClRoZSBtb3N0IHBvcHVsYXIgdGVtcGVyYXR1cmUgdHJlYXRtZW50cyBhcmUgMTUsIDIwLCAyNSwgMzAsIGFuZCAzNS4KCiMgRXhwbG9yYXRvcnkgR3JhcGhzClRoZXNlIGdyYXBocyByZXByZXNlbnQgc29tZSBlYXJseSBkYXRhIGV4cGxvcmF0aW9uLCB1c2luZyB0aGUgc3Vic2V0IG9mIHRoZSBkYXRhIHRoYXQgY29udGFpbnMgYm90aCBzdXJ2aXZhbCBhbmQgZGV2ZWxvcG1lbnQgdGltZSBmb3IgdGhlIHRocmVlIG1haW4gbGlmZXN0YWdlcyAoZWdnLCBsYXJ2YSwgcHVwYSkuIApgYGB7cn0KZHJoaXN0IDwtIGdncGxvdChRbWV0cmljcywgYWVzKHggPSBob3RzKSkrCiAgZ2VvbV9oaXN0b2dyYW0oKSArCiAgeGxhYigidGVtcHMgYWJvdmUgZHIgb3B0aW11bSIpKwogIHRoZW1lX2Nvd3Bsb3QoKQpzdXJ2aXZhbGhpc3QgPC0gZ2dwbG90KFFtZXRyaWNzLCBhZXMoeCA9IGhvdHMxKSkrCiAgZ2VvbV9oaXN0b2dyYW0oKSArCiAgeGxhYigidGVtcHMgYWJvdmUgc3Vydml2YWwgb3B0aW11bSIpKwogIHRoZW1lX2Nvd3Bsb3QoKQpwbG90X2dyaWQoZHJoaXN0LCBzdXJ2aXZhbGhpc3QpCgpgYGAKRmlndXJlIDYuIEhpc3RvZ3JhbXMgc2hvd2luZyBtb3N0IHNldHMgaW4gdGhlICJpbnRlciIgc3Vic2V0IGluY2x1ZGUgYXQgbGVhc3Qgb25lIHRlbXBlcmF0dXJlIGFib3ZlIHRoZSBkciBvcHRpbXVtIGFuZCBtdWx0cGxlIGFib3ZlIHRoZSBzdXJ2aXZhbCBvcHRpbXVtCgojIFNjYWxlIGRldmVsb3BtZW50IHRpbWUKRnVuY3Rpb24gdG8gZXh0cmFjdCBsb25nZXN0IGRldmVsb3BtZW50IHRpbWUgYnkgc2V0IGFuZCBjcmVhdGUgYSBuZXcgY29sdW1uIHdpdGggc2NhbGVkIGRldmVsb3BtZW50IHRpbWUuIApzX2R0ID0gMSAtIChkdC9tYXhkdCkuCmBgYHtyfQpzY2FsZS5kdCA8LSBmdW5jdGlvbih0YWJsZSl7CiAgbWF4ZHQgPC0gbWF4KHRhYmxlJGR0LCBuYS5ybSA9IFQpCiAgdGFibGUkc19kdCA8LSAxIC0gKHRhYmxlJGR0L21heGR0KQogIHRhYmxlCn0KYGBgCgoKQXBwbHkgdGhlIGZ1bmN0aW9uIHRvIGVhY2ggc2V0IGFuZCBhZGQgc19kdCBjb2x1bW4gKHNjYWxlZCBkdCkKYGBge3J9CmludGVyIDwtIGludGVyICU+JSAKICBncm91cF9ieShzZXQpICU+JSAKICBuZXN0KCkgJT4lIAogIG11dGF0ZShzX2R0ID0gbWFwKGRhdGEsIHNjYWxlLmR0KSkgJT4lIAogIHVubmVzdChjb2xzID0gc19kdCkgJT4lIAogIHNlbGVjdCgtZGF0YSkKYGBgCgpQbG90IHRvIGNoZWNrIHRoYXQgc19kdCB3YXMgY2FsY3VsYXRlZCBwcm9wZXJseQpgYGB7cn0KZ2dwbG90KGZpbHRlcihpbnRlciwgc2V0ID09IDk0MXxzZXQgPT0gMTE3OXwgc2V0ID09IDMpLCBhZXMoeCA9IGR0LCB5ID0gc19kdCwgY29sID0gZmFjdG9yKHNldCkpKSsKICBnZW9tX3BvaW50KCkrCiAgc2NhbGVfY29sb3JfdmlyaWRpc19kKCkrCiAgdGhlbWVfY293cGxvdCgpCmBgYApkdDogZGV2ZWxvcG1lbnQgdGltZSwgc19kdCwgc2NhbGVkIGRldmVsb3BtZW50IHRpbWUgKDAgZm9yIGxvbmdlc3QpCgpgYGB7cn0KZWdnIDwtIGludGVyW2ludGVyJGxpZmVzdGFnZSA9PSAiZWdnIiwgXQplZ2ckc2V0IDwtIGZhY3RvcihlZ2ckc2V0KQpsYXJ2YSA8LSBpbnRlcltpbnRlciRsaWZlc3RhZ2UgPT0gImxhcnZhIiwgXQpsYXJ2YSRzZXQgPC0gZmFjdG9yKGxhcnZhJHNldCkKcHVwYSA8LSBpbnRlcltpbnRlciRsaWZlc3RhZ2UgPT0gInB1cGEiLCBdCnB1cGEkc2V0IDwtIGZhY3RvcihwdXBhJHNldCkKYGBgCgojIyBHcmFwaCB0aGUgc3Vydml2YWwgZGF0YSB2cy4gdGVtcGVyYXR1cmUgd2l0aGluIGVhY2ggbGlmZXN0YWdlLCB3aXRoIGVhY2ggc2V0IGFzIGEgbGluZSwgZmFjZXRlZCBieSBmYW1pbHkgCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBlZ2csIGFlcyh4ID0gdGVtcCwgeSA9IHN1cnZpdmFsLCBjb2xvciA9IHNldCwgZ3JvdXAgPSBzZXQpKSArIAogIGdlb21fbGluZSgpICsKICBmYWNldF93cmFwKH5mYW1pbHkpICsgCiAgbGFicyh4ID0gIlRlbXBlcmF0dXJlIiwgeSA9ICJTdXJ2aXZhbCAocGVyY2VudGFnZSkiLCB0aXRsZSA9ICJFZ2cgU3Vydml2YWwiKQpgYGAKRmlndXJlIDUuIEVnZyBzdXJ2aXZhbCBhdCBhIHJhbmdlIG9mIHRlbXBlcmF0dXJlcywgZmFjZXRlZCBieSBmYW1pbHkuIAoKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGxhcnZhLCBhZXMoeCA9IHRlbXAsIHkgPSBzdXJ2aXZhbCwgY29sb3IgPSBzZXQsIGdyb3VwID0gc2V0KSkgKyAKICBnZW9tX2xpbmUoKSArCiAgZmFjZXRfd3JhcCh+ZmFtaWx5KSArIAogIGxhYnMoeCA9ICJUZW1wZXJhdHVyZSIsIHkgPSAiU3Vydml2YWwgKHBlcmNlbnRhZ2UpIiwgdGl0bGUgPSAiTGFydmFsIFN1cnZpdmFsIikKYGBgCkZpZ3VyZSA2LiBMYXJ2YWwgc3Vydml2YWwgYXQgYSByYW5nZSBvZiB0ZW1wZXJhdHVyZXMsIGZhY2V0ZWQgYnkgZmFtaWx5LiAKCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBwdXBhLCBhZXMoeCA9IHRlbXAsIHkgPSBzdXJ2aXZhbCwgY29sb3IgPSBzZXQsIGdyb3VwID0gc2V0KSkgKyAKICBnZW9tX2xpbmUoKSArCiAgZmFjZXRfd3JhcCh+ZmFtaWx5KSArIAogIGxhYnMoeCA9ICJUZW1wZXJhdHVyZSIsIHkgPSAiU3Vydml2YWwgKHBlcmNlbnRhZ2UpIiwgdGl0bGUgPSAiUHVwYWwgU3Vydml2YWwiKQpgYGAKRmlndXJlIDcuIFB1cGFsIHN1cnZpdmFsIGF0IGEgcmFuZ2Ugb2YgdGVtcGVyYXR1cmVzLCBmYWNldGVkIGJ5IGZhbWlseS4gCgoKIyMgR3JhcGggdGhlIGRldmVsb3BtZW50IHRpbWUgZGF0YSB2cy4gdGVtcGVyYXR1cmUgd2l0aGluIGVhY2ggbGlmZXN0YWdlLCB3aXRoIGVhY2ggc2V0IGFzIGEgbGluZSwgZmFjZXRlZCBieSBmYW1pbHkKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGVnZywgYWVzKHggPSB0ZW1wLCB5ID0gZHQsIGNvbG9yID0gc2V0LCBncm91cCA9IHNldCkpICsgCiAgZ2VvbV9saW5lKCkgKwogIGZhY2V0X3dyYXAofmZhbWlseSkgKyAKICBsYWJzKHggPSAiVGVtcGVyYXR1cmUiLCB5ID0gIkRldmVsb3BtZW50IHRpbWUgKGRheXMpIiwgdGl0bGUgPSAiRWdnIERldmVsb3BtZW50IFRpbWUiKQpgYGAKRmlndXJlIDguIEVnZyBkZXZlbG9wbWVudCB0aW1lIGF0IGEgcmFuZ2Ugb2YgdGVtcGVyYXR1cmVzLCBmYWNldGVkIGJ5IGZhbWlseS4gCgoKYGBge3J9CmdncGxvdChkYXRhID0gbGFydmEsIGFlcyh4ID0gdGVtcCwgeSA9IGR0LCBjb2xvciA9IHNldCwgZ3JvdXAgPSBzZXQpKSArIAogIGdlb21fbGluZSgpICsKICBmYWNldF93cmFwKH5mYW1pbHkpICsgCiAgbGFicyh4ID0gIlRlbXBlcmF0dXJlIiwgeSA9ICJEZXZlbG9wbWVudCB0aW1lIChkYXlzKSIsIHRpdGxlID0gIkxhcnZhbCBEZXZlbG9wbWVudCBUaW1lIikKYGBgCkZpZ3VyZSA5LiBMYXJ2YWwgZGV2ZWxvcG1lbnQgdGltZSBhdCBhIHJhbmdlIG9mIHRlbXBlcmF0dXJlcywgZmFjZXRlZCBieSBmYW1pbHkuIAoKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IHB1cGEsIGFlcyh4ID0gdGVtcCwgeSA9IGR0LCBjb2xvciA9IHNldCwgZ3JvdXAgPSBzZXQpKSArIAogIGdlb21fbGluZSgpICsKICBmYWNldF93cmFwKH5mYW1pbHkpICsgCiAgbGFicyh4ID0gIlRlbXBlcmF0dXJlIiwgeSA9ICJEZXZlbG9wbWVudCB0aW1lIChkYXlzKSIsIHRpdGxlID0gIlB1cGFsIERldmVsb3BtZW50IFRpbWUiKQpgYGAKRmlndXJlIDEwLiBQdXBhbCBkZXZlbG9wbWVudCB0aW1lIGF0IGEgcmFuZ2Ugb2YgdGVtcGVyYXR1cmVzLCBmYWNldGVkIGJ5IGZhbWlseS4gCgojIyBPdGhlciBleHBsb3JhdG9yeSBncmFwaHMKCiMjIyBOb2N0dWlkcyAtIGFuIGV4YW1wbGUgb2YgZmFtaWx5LXNwZWNpZmljIGdyYXBocwoKYGBge3J9CmdncGxvdChkYXRhID0gZmlsdGVyKGVnZywgZmFtaWx5ID09ICJOb2N0dWlkYWUiKSwgYWVzKHggPSB0ZW1wLCB5ID0gc19kdCwgY29sb3IgPSBzZXQsIGdyb3VwID0gc2V0KSkgKyAKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBmaWx0ZXIoZWdnLCBmYW1pbHkgPT0gIk5vY3R1aWRhZSIpLCBtYXBwaW5nID0gYWVzKHggPSB0ZW1wLCB5ID0gc3Vydml2YWwvMTAwLCBjb2xvciA9IHNldCwgZ3JvdXAgPSBzZXQpLCBsaW5ldHlwZSA9IDIpKwogIGZhY2V0X3dyYXAofnNwKSArIAogIGxhYnMoeCA9ICJUZW1wZXJhdHVyZSIsIHkgPSAiU2NhbGVkIGR0IC8gU3Vydml2YWwgKGRhc2hlZCkiLCB0aXRsZSA9ICJOb2N0dWlkIEVnZyBEZXZlbG9wbWVudCBhbmQgU3Vydml2YWwiKQpgYGAKRmlndXJlIDExLiBFZ2cgZGV2ZWxvcG1lbnQgcmF0ZSBhbmQgc3Vydml2YWwgaW4gdGhlIE5vY3R1aWRhZSBmYW1pbHksIGZhY2V0ZWQgYnkgc3BlY2llcy4gCgoKYGBge3J9CmdncGxvdChkYXRhID0gZmlsdGVyKGxhcnZhLCBmYW1pbHkgPT0gIk5vY3R1aWRhZSIpLCBhZXMoeCA9IHRlbXAsIHkgPSBzX2R0LCBjb2xvciA9IHNldCwgZ3JvdXAgPSBzZXQpKSArIAogIGdlb21fbGluZSgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGZpbHRlcihsYXJ2YSwgZmFtaWx5ID09ICJOb2N0dWlkYWUiKSwgbWFwcGluZyA9IGFlcyh4ID0gdGVtcCwgeSA9IHN1cnZpdmFsLzEwMCwgY29sb3IgPSBzZXQsIGdyb3VwID0gc2V0KSwgbGluZXR5cGUgPSAyKSsKICBmYWNldF93cmFwKH5zcCkgKyAKICBsYWJzKHggPSAiVGVtcGVyYXR1cmUiLCB5ID0gIlNjYWxlZCBkZXYgdGltZSAvIFN1cnZpdmFsIChkYXNoZWQpIiwgdGl0bGUgPSAiTm9jdHVpZCBMYXJ2YWwgRGV2ZWxvcG1lbnQgYW5kIFN1cnZpdmFsIikKYGBgCkZpZ3VyZSAxMi4gTGFydmFsIGRldmVsb3BtZW50IHJhdGUgYW5kIHN1cnZpdmFsIGluIHRoZSBOb2N0dWlkYWUgZmFtaWx5LCBmYWNldGVkIGJ5IHNwZWNpZXMuIAoKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGZpbHRlcihwdXBhLCBmYW1pbHkgPT0gIk5vY3R1aWRhZSIpLCBhZXMoeCA9IHRlbXAsIHkgPSBzX2R0LCBjb2xvciA9IHNldCwgZ3JvdXAgPSBzZXQpKSArIAogIGdlb21fbGluZSgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGZpbHRlcihwdXBhLCBmYW1pbHkgPT0gIk5vY3R1aWRhZSIpLCBtYXBwaW5nID0gYWVzKHggPSB0ZW1wLCB5ID0gc3Vydml2YWwvMTAwLCBjb2xvciA9IHNldCwgZ3JvdXAgPSBzZXQpLCBsaW5ldHlwZSA9IDIpKwogIGZhY2V0X3dyYXAofnNwKSArIAogIGxhYnMoeCA9ICJUZW1wZXJhdHVyZSIsIHkgPSAiU2NhbGVkIGRldiB0aW1lIC8gU3Vydml2YWwgKGRhc2hlZCkiLCB0aXRsZSA9ICJOb2N0dWlkIFB1cGFsIERldmVsb3BtZW50IGFuZCBTdXJ2aXZhbCIpCmBgYApGaWd1cmUgMTMuIFB1cGFsIGRldmVsb3BtZW50IHJhdGUgYW5kIHN1cnZpdmFsIGluIHRoZSBOb2N0dWlkYWUgZmFtaWx5LCBmYWNldGVkIGJ5IHNwZWNpZXMuIAoKIyBDdW1tdWxhdGl2ZSBzdXJ2aXZhbCBncmFwaHMKRm9yIHN0dWRpZXMgdGhhdCByZXBvcnQgc3Vydml2YWwgb2YgZWdncywgbGFydmFlIGFuZCBwdXBhLCBtYWtlIGdyYXBocyBvZiBjdW1tdWxhdGl2ZSBzdXJ2aXZhbDoKIApgYGB7cn0KIyBnZXQgaWRzIG9mIHNldHMgdGhhdCByZXBvcnQgc3Vydml2YWwgaW4gYWxsIHRocmVlIGxpZmUgc3RhZ2VzCmVnZyA8LSBmaWx0ZXIoaW50ZXIsIGxpZmVzdGFnZSA9PSAiZWdnIiwgc3Vydml2YWwgPj0gMCkKZWdnJHNldCA8LSBmYWN0b3IoZWdnJHNldCkKbGFydmEgPC0gZmlsdGVyKGludGVyLCBsaWZlc3RhZ2UgPT0gImxhcnZhIiwgIHN1cnZpdmFsID49IDEpCmxhcnZhJHNldCA8LSBmYWN0b3IobGFydmEkc2V0KQpwdXBhIDwtIGZpbHRlcihpbnRlciwgbGlmZXN0YWdlID09ICJwdXBhIiwgIHN1cnZpdmFsID49IDEpCnB1cGEkc2V0IDwtIGZhY3RvcihwdXBhJHNldCkKCmVnZ19pZHMgPC0gdGliYmxlKGlkID0gdW5pcXVlKGVnZyRpZCkpCmxhcnZhX2lkcyA8LSB0aWJibGUoaWQgPSB1bmlxdWUobGFydmEkaWQpKQpwdXBhX2lkcyA8LSB0aWJibGUoaWQgPSB1bmlxdWUocHVwYSRpZCkpCgpmdWxsc3R1ZGllczEgPC0gaW50ZXJzZWN0KGVnZ19pZHMsbGFydmFfaWRzKQpmdWxsc3R1ZGllcyA8LSBpbnRlcnNlY3QoZnVsbHN0dWRpZXMxLHB1cGFfaWRzKQojIHRoZSBuZXcgdGFibGUgIm9udG9zdXJ2aXZhbCIgY29udGFpbnMgb25seSB0aG9zZSBzZXRzCm9udG9zdXJ2aXZhbCA8LSBpbnRlciAlPiUgZmlsdGVyKGlkICVpbiUgZnVsbHN0dWRpZXMkaWQpCm9udG9zdXJ2aXZhbCRzdGFnZW51bSA8LSBpZmVsc2Uob250b3N1cnZpdmFsJGxpZmVzdGFnZSA9PSAiZWdnIiwgMSwgaWZlbHNlKG9udG9zdXJ2aXZhbCRsaWZlc3RhZ2UgPT0gImxhcnZhIiwyLCAzKSkKYGBgCgoKIyBNYWtpbmcgYSBncmFwaCB3aXRoIGN1bXVsYXRpdmUgc3Vydml2YWwKSGVyZSwgSSBjYWxjdWxhdGUgY3VtdWxhdGl2ZS90b3RhbCBzdXZpdmFsIGF0IGVhY2ggdGVtcCBmb3IgZWFjaCBzZXQgYW5kIGF0dGVtcHQgdG8gcGxvdCBpdC4gCmBgYHtyfQpoZWFkKG9udG9zdXJ2aXZhbCkKCmNvbWJzdXJ2aXZhbCA8LSBvbnRvc3Vydml2YWxbLCBjKCJzZXQiLCAiaWQiLCAic3AiLCAibGlmZXN0YWdlIiwgInRlbXAiLCAic3Vydml2YWwiLCAic3RhZ2VudW0iKV0KYGBgCgpgYGB7cn0KCgpgYGAKCg==